#include "ZExt.h"
#include <assert.h>

ZExt::ZExt(void):out(&buf)
{
	/* allocate deflate state */
	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;
}


ZExt::~ZExt(void)
{
}
void ZExt::clearBuf(){
	buf.clear();
}
string ZExt::bufStr(){
	return buf.str();
}
size_t ZExt::readBuf(unsigned char* _b,size_t blen){
	buf.read((char*)_b,blen);
	return buf.gcount();
}
void ZExt::initDeflate(int lev){
	int ret = deflateInit(&strm, lev);
	assert(ret == Z_OK);
}
void ZExt::initInflate(){
	int ret = inflateInit(&strm);
	assert(ret == Z_OK);
}
void ZExt::ostream(basic_ostream<char>* _out){
	assert(_out&&!_out->eof());
	this->out=_out;
}
int ZExt::deflat(string data,int finish){
	return this->deflat((unsigned char*)data.c_str(),data.length(),finish);
}
int ZExt::deflat(unsigned char* data,size_t len,int finish){
	assert(len>0);
	int ret;
	strm.avail_in =(uInt) len;
	strm.next_in = data;
	do {
		strm.avail_out = ZEXT_CHUNK;
		strm.next_out = obuf;
		ret = deflate(&strm, finish);    /* no bad return value */
		assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
		uInt have = ZEXT_CHUNK - strm.avail_out;
		this->out->write((const char*)this->obuf,have);
	} while (strm.avail_out == 0);
	assert(strm.avail_in == 0);
	return ret;
}
int ZExt::deflat(basic_istream<char>* _in){
	int flush,ret;
	do {
		_in->read((char*)this->ibuf,ZEXT_CHUNK);
		flush =_in->eof() ? Z_FINISH : Z_NO_FLUSH;
		ret=this->deflat(this->ibuf,_in->gcount(),flush);
	} while (flush != Z_FINISH);
	assert(ret == Z_STREAM_END);
	return ret;
}
int ZExt::inflat(unsigned char* data,size_t len,int finish){
	assert(len>0);
	strm.avail_in =(uInt) len;
	strm.next_in = data;
	int ret;
	do {
		strm.avail_out = ZEXT_CHUNK;
		strm.next_out = obuf;
		ret = inflate(&strm, finish);
		assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
		switch (ret) {
		case Z_NEED_DICT:
			ret = Z_DATA_ERROR;     /* and fall through */
			return ret;
		case Z_DATA_ERROR:
		case Z_MEM_ERROR:
			return ret;
		}
		uInt have = ZEXT_CHUNK - strm.avail_out;
		this->out->write((const char*)this->obuf,have);
	} while (strm.avail_out == 0);
	assert(strm.avail_in == 0);
	return ret;
}
int ZExt::inflat(basic_istream<char>* _in){
	int flush,ret;
	do {
		_in->read((char*)this->ibuf,ZEXT_CHUNK);
		flush =_in->eof() ? Z_FINISH : Z_NO_FLUSH;
		ret=this->inflat(this->ibuf,_in->gcount(),flush);
	} while (flush != Z_FINISH);
	assert(ret == Z_STREAM_END);
	return ret;
}
